﻿// -----------------------------------------------------------------------
// <copyright file="LinearConvolution.cs" company="FCIS">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace IP_Package.Operations.Neighbor_operations
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using IP_Package.Operations.Restoration.RemoveNoise;
    using IPPackage;
    using IPPackage.ImageOperation;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class LinearConvolution : Operation
    {
        /// <summary>
        /// Adds the border.
        /// </summary>
        /// <param name="maskSize">Size of the mask.</param>
        /// <returns>new buffer</returns>
        public Color[,] AddBorder(double maskSize)
        {
            try
            {
                int borderSize = (int)(((int)maskSize / 2) * 2);
                Color[,] newBuffer = new Color[this.BufferOfImage.GetLength(0) + borderSize, this.BufferOfImage.GetLength(1) + borderSize];
                for (int i = 0; i < this.BufferOfImage.GetLength(1) + borderSize; i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0) + borderSize; j++)
                    {
                        if (i < (int)(maskSize / 2) || i >= this.BufferOfImage.GetLength(1))
                        {
                            if ((i >= this.BufferOfImage.GetLength(1)) && (j >= this.BufferOfImage.GetLength(0)))
                            {
                                newBuffer[j, i] = Color.FromArgb(0, 0, 0);
                            }
                            else if (i >= this.BufferOfImage.GetLength(1))
                            {
                                newBuffer[j, i] = this.BufferOfImage[j, this.BufferOfImage.GetLength(1) - (i % this.BufferOfImage.GetLength(1)) - 1];
                            }
                            else if (j >= this.BufferOfImage.GetLength(0))
                            {
                                newBuffer[j, i] = this.BufferOfImage[this.BufferOfImage.GetLength(0) - (j % this.BufferOfImage.GetLength(0)) - 1, i];
                            }
                            else
                            {
                                newBuffer[j, i] = this.BufferOfImage[j, i];
                            }
                        }
                        else if (j < (int)(maskSize / 2) || j >= this.BufferOfImage.GetLength(0))
                        {
                            if ((i >= this.BufferOfImage.GetLength(1)) && (j >= this.BufferOfImage.GetLength(0)))
                            {
                                newBuffer[j, i] = this.BufferOfImage[this.BufferOfImage.GetLength(0) - (j % this.BufferOfImage.GetLength(0)) - 1, this.BufferOfImage.GetLength(1) - (i % this.BufferOfImage.GetLength(1)) - 1];
                            }
                            else if (i >= this.BufferOfImage.GetLength(1))
                            {
                                newBuffer[j, i] = this.BufferOfImage[j, this.BufferOfImage.GetLength(1) - (i % this.BufferOfImage.GetLength(1)) - 1];
                            }
                            else if (j >= this.BufferOfImage.GetLength(0))
                            {
                                newBuffer[j, i] = this.BufferOfImage[this.BufferOfImage.GetLength(0) - (j % this.BufferOfImage.GetLength(0)) - 1, i];
                            }
                            else
                            {
                                newBuffer[j, i] = this.BufferOfImage[j, i];
                            }
                        }
                        else
                        {
                            newBuffer[j, i] = this.BufferOfImage[j - (int)(maskSize / 2), i - (int)(maskSize / 2)];
                        }
                    }
                }

                return newBuffer;
            }
            catch (Exception ex)
            {
                IPPackage.Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// make Linears convolution with any mask to any picture.
        /// </summary>
        /// <param name="bufferOfImage">The buffer of image.</param>
        /// <param name="mask">The mask.</param>
        /// <param name="postOperation">The post operation.</param>
        /// <returns>the new image</returns>
        public Bitmap LinearConvolutionFn(Color[,] bufferOfImage, Mask mask, string postOperation)
        {
            try
            {
                double[,] redBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                double[,] greenBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                double[,] blueBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                Bitmap newImg = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                int width = bufferOfImage.GetLength(0) - (mask.MaskSize / 2);
                    int height = bufferOfImage.GetLength(1) - (mask.MaskSize / 2);
                    int w = 0;
                    int h = 0;
                    double newRed = 0, newBlue = 0, newGreen = 0;
                    this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                    for (int i = mask.MaskSize / 2; i < height; i++, h++)
                    {
                        for (int j = mask.MaskSize / 2; j < width; j++, w++)
                        {
                            int tempHieght = -mask.MaskSize / 2;
                            int tempWidth = -mask.MaskSize / 2;
                            for (int im = 0; im < mask.MaskSize; im++)
                            {
                                for (int jm = 0; jm < mask.MaskSize; jm++)
                                {
                                    newRed += mask.MaskValues[jm, im] * (double)bufferOfImage[j + tempWidth, i + tempHieght].R;
                                    newBlue += mask.MaskValues[jm, im] * (double)bufferOfImage[j + tempWidth, i + tempHieght].B;
                                    newGreen += mask.MaskValues[jm, im] * (double)bufferOfImage[j + tempWidth, i + tempHieght].G;
                                    tempWidth++;
                                }

                                tempWidth = -mask.MaskSize / 2;
                                tempHieght++;
                            }

                            if (postOperation == "None")
                            {
                                this.NewBufferOfImage[w, h] = Color.FromArgb((int)newRed, (int)newGreen, (int)newBlue);
                                newImg.SetPixel(w, h, this.NewBufferOfImage[w, h]);
                                newRed = 0;
                                newBlue = 0;
                                newGreen = 0;
                            }
                            else if (postOperation == "Normalization")
                            {
                                redBuffer[w, h] = newRed;
                                greenBuffer[w, h] = newGreen;
                                blueBuffer[w, h] = newBlue;
                                newRed = 0;
                                newBlue = 0;
                                newGreen = 0;
                            }
                            else if (postOperation == "Cutoff")
                            {
                                if (newRed > 255)
                                {
                                    newRed = 255;
                                }
                                else if (newRed < 0)
                                {
                                    newRed = 0;
                                }

                                if (newGreen > 255)
                                {
                                    newGreen = 255;
                                }
                                else if (newGreen < 0)
                                {
                                    newGreen = 0;
                                }

                                if (newBlue > 255)
                                {
                                    newBlue = 255;
                                }
                                else if (newBlue < 0)
                                {
                                    newBlue = 0;
                                }

                                this.NewBufferOfImage[w, h] = Color.FromArgb((int)newRed, (int)newGreen, (int)newBlue);
                                newImg.SetPixel(w, h, this.NewBufferOfImage[w, h]);
                                newRed = 0;
                                newBlue = 0;
                                newGreen = 0;
                            }
                        }

                        w = 0;
                    }

                    if (postOperation == "Normalization")
                    {
                        Global_applications.Global_methods_user useMethods = new Global_applications.Global_methods_user();
                        useMethods.BufferOfImage = this.BufferOfImage;
                        newImg = useMethods.Normalization(redBuffer, greenBuffer, blueBuffer);
                        this.NewBufferOfImage = useMethods.NewBufferOfImage;
                    }

                return newImg;
            }
            catch (Exception ex)
            {
                IPPackage.Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Linears the convolution orderd filter fn.
        /// </summary>
        /// <param name="bufferOfImage">The buffer of image.</param>
        /// <param name="maskSize">Size of the mask.</param>
        /// <param name="type">The type.</param>
        /// <returns>result image after order filter</returns>
        public Bitmap LinearConvolutionOrderdFilterFn(Color[,] bufferOfImage, int maskSize, string type)
        {
            double[,] redBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] greenBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] blueBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            Bitmap newImg = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
            int width = bufferOfImage.GetLength(0) - (maskSize / 2);
            int height = bufferOfImage.GetLength(1) - (maskSize / 2);
            int w = 0;
            int h = 0;
            this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
            for (int i = maskSize / 2; i < height; i++, h++)
            {
                for (int j = maskSize / 2; j < width; j++, w++)
                {
                    int tempHieght = -maskSize / 2;
                    int tempWidth = -maskSize / 2;
                    Color[,] window = new Color[maskSize, maskSize];
                    for (int im = 0; im < maskSize; im++)
                    {
                        for (int jm = 0; jm < maskSize; jm++)
                        {
                            window[im, jm] = bufferOfImage[j + tempWidth, i + tempHieght];
                            tempWidth++;
                        }

                        tempWidth = -maskSize / 2;
                        tempHieght++;
                    }

                    ApplicationOfSortAndMaxAndMin filter = new ApplicationOfSortAndMaxAndMin();
                    MixedColor[] xvalAndYVal = filter.GetValue(window, type);
                    if (type == "Midpoint")
                    {
                        int tempR = (window[xvalAndYVal[0].X, xvalAndYVal[0].Y].R + window[xvalAndYVal[1].X, xvalAndYVal[1].Y].R) / 2;
                        int tempG = (window[xvalAndYVal[0].X, xvalAndYVal[0].Y].R + window[xvalAndYVal[1].X, xvalAndYVal[1].Y].G) / 2;
                        int tempB = (window[xvalAndYVal[0].X, xvalAndYVal[0].Y].R + window[xvalAndYVal[1].X, xvalAndYVal[1].Y].B) / 2;
                        this.NewBufferOfImage[w, h] = Color.FromArgb(tempR, tempG, tempB);
                    }
                    else
                    {
                        this.NewBufferOfImage[w, h] = window[xvalAndYVal[0].X, xvalAndYVal[0].Y];
                    }

                    newImg.SetPixel(w, h, this.NewBufferOfImage[w, h]);
                }

                w = 0;
            }

            return newImg;
        }

        /// <summary>
        /// Linears the convolution geometric fn.
        /// </summary>
        /// <param name="bufferOfImage">The buffer of image.</param>
        /// <param name="mask">The mask.</param>
        /// <returns>the result image after geometric function</returns>
        public Bitmap LinearConvolutionGeometricFn(Color[,] bufferOfImage, double mask)
        {
            double[,] redBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] greenBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] blueBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            Bitmap newImg = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
            int width = bufferOfImage.GetLength(0) - (int)(mask / 2);
            int height = bufferOfImage.GetLength(1) - (int)(mask / 2);
            int w = 0;
            int h = 0;
            double newRed = 1, newBlue = 1, newGreen = 1;
            this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
            for (int i = (int)mask / 2; i < height; i++, h++)
            {
                for (int j = (int)mask / 2; j < width; j++, w++)
                {
                    int tempHieght = -(int)mask / 2;
                    int tempWidth = -(int)mask / 2;
                    for (int im = 0; im < (int)mask; im++)
                    {
                        for (int jm = 0; jm < (int)mask; jm++)
                        {
                            double orgImgR, orgImgB, orgImgG;
                            orgImgR = (double)bufferOfImage[j + tempWidth, i + tempHieght].R;
                            orgImgB = (double)bufferOfImage[j + tempWidth, i + tempHieght].B;
                            orgImgG = (double)bufferOfImage[j + tempWidth, i + tempHieght].G;
                            if (bufferOfImage[j + tempWidth, i + tempHieght].R == 0)
                            {
                                orgImgR = 1;
                            }

                            if (bufferOfImage[j + tempWidth, i + tempHieght].B == 0)
                            {
                                orgImgB = 1;
                            }

                            if (bufferOfImage[j + tempWidth, i + tempHieght].G == 0)
                            {
                                orgImgG = 1;
                            }

                            newRed *= orgImgR;
                            newBlue *= orgImgB;
                            newGreen *= orgImgG;
                            tempWidth++;
                        }

                        tempWidth = -(int)mask / 2;
                        tempHieght++;
                    }

                    newRed = Math.Pow(newRed, (1 / (double)(mask * mask)));
                    newBlue = Math.Pow(newBlue, (1 / (double)(mask * mask)));
                    newGreen = Math.Pow(newGreen, (1 / (double)(mask * mask)));
                    this.NewBufferOfImage[w, h] = Color.FromArgb((int)newRed, (int)newGreen, (int)newBlue);
                    newImg.SetPixel(w, h, this.NewBufferOfImage[w, h]);
                    newRed = 1;
                    newBlue = 1;
                    newGreen = 1;
                }

                w = 0;
            }

            return newImg;
        }
    }
}
